//Thread of the "output" window: on this window the grid of the memory is displayed

#include "out_main.h"
#include "main.h"

//void print_info (char *format);

int execute_instr(Memoire &mem, int *p_index, SDL_Surface *ecran, Uint32 couleurs[]);



void *out_main(void* val){
	par *valeur=(par*)val;

	srand((int) time(NULL));

//--------------------------------
	SDL_Surface *ecran = initSDL(LARGEUR, HAUTEUR);

	Uint32 couleurs[NB_COULEURS];
	initCouleurs(couleurs, ecran);

		//mouse
	SDL_WarpMouse(ecran->w/2, ecran->h/2);

	clearScr(couleurs[C_BLEU_FONCE], ecran);

	//trac� du quadrillage :
	for(int i=0; i<=HAUTEUR; i+=PAS)
		lineHor(0, i, LARGEUR, couleurs[C_VERT_FONCE], ecran);
	for(int j=0; j<=LARGEUR; j+=PAS)
		lineVert(j, 0, HAUTEUR, couleurs[C_VERT_FONCE], ecran);

	//sauvegarde de l'�cran
	SDL_SaveBMP(ecran,"data.dat");
	SDL_Surface *imgEcran = SDL_LoadBMP("data.dat");
	remove("data.dat");

	SDL_Rect pos={0};
//--------------------------------
	{
		//affichage du titre
		SDL_Rect posTitle;
		SDL_Surface *title = NULL;
		title = SDL_LoadBMP("title.dat");
		if(title == NULL){
			fprintf(stderr, "Erreur de chargement de l'image d'accueil !\n");
                        exit(EXIT_FAILURE);
		}else{
			posTitle.x = 0;
			posTitle.y = 200;
			SDL_SetColorKey(title, SDL_SRCCOLORKEY, 0);
			SDL_BlitSurface(title, NULL, ecran, &posTitle);
		}

		SDL_Flip(ecran);	//actualisation
		SDL_Delay(500);

		//fondu
		for(int i=255; i>0; i-=10+255/i){
			SDL_SetAlpha(title, SDL_SRCALPHA, i);
			SDL_BlitSurface(imgEcran, NULL, ecran, &pos);	//on efface le titre
			SDL_BlitSurface(title, NULL, ecran, &posTitle);	//on recolle le titre
			SDL_Flip(ecran);
			SDL_Delay(5);
		}

		SDL_FreeSurface(title);
	}

	SDL_BlitSurface(imgEcran, NULL, ecran, &pos);	//on efface le titre
//--------------------------------
	int nb_prog=0;

	int entree_mem[50];	//position where the programs will be loaded
	int index_prog[50];// � modifier la methode pr g�rer la taille : faire une cste NB_PROG_MAX, et v�rifier qu'on n'en charge pas plus

	//cr�ation de la m�moire
	Memoire mem;

	int sve, ret;
	int tps1 = SDL_GetTicks(), tps2=0;

	//-------------------------------  main loop  ----------------------------------------------
	while(valeur->loop_ok){
		do{
			//gestion temps
			do{
				if(gestion_evt()==1){
					valeur->loop_ok=false;
					break;
				}
				tps2 = SDL_GetTicks();
			}while(tps1 + valeur->speed > tps2);	//tant qu'on a pas attendu TPS ms depuis le dernier passage
			tps1 = SDL_GetTicks();

			SDL_Flip(ecran);//actualisation
		}while(!(valeur->play) && (valeur->loop_ok) && !(valeur->full));



		for(int i=0; i<nb_prog; i++){	//on parcourt tous les programmes
			sve=index_prog[i];//sauvegarde de l'index m�moire
			sve=sve%TAILLE_MEM; //utile ?
			ret = execute_instr(mem, &sve, ecran, couleurs);	//ex�cution de l'instruction
			if(ret == 1){
				printf("Le prog %d a perdu !", i);
			}
			mem.setCouleur(index_prog[i], index_prog[i], ecran, couleurs, 0);	//on enleve le statut "actif" sur la cellule
			if(index_prog[i] == sve)	//l'entr�e m�moire n'a pas �t� chang�e (par JMP par ex)
				index_prog[i]++;
			else
				index_prog[i]=sve;
			mem.setCouleur(index_prog[i], index_prog[i], ecran, couleurs, 1);
		}

	//--------------
		if(valeur->full){	//a new file is to be loaded
			mem.raz();
			valeur->full=false;
			nb_prog=valeur->liste_files.size();//l_nbElt(valeur->liste_files);

			for(int i=0; i<nb_prog; i++){
				int rand_nb=(i*(TAILLE_MEM/nb_prog) + (int)(rand()%1000))%TAILLE_MEM;
				printf("entree %d: %d\n", i, rand_nb);
				entree_mem[i]=rand_nb;
				index_prog[i]=rand_nb;
			}

			//chargement du fichier dans la m�moire
			//llist tmp_list = valeur->liste_files;
			for(int i=0; i<nb_prog; i++){
				loadFile(mem, entree_mem[i], valeur->liste_files[i]);//tmp_list->name);
				//tmp_list = tmp_list->next;
			}

			//color
			mem.setCouleur(0, TAILLE_MEM-1, ecran, couleurs, 0);//0 si doit mettre couleur correspondant � l'op�ration
			for(int i=0; i<nb_prog; i++){
				mem.setCouleur(index_prog[i], index_prog[i], ecran, couleurs, 1);//1 si doit mettre couleur indiquant actif
			}
			SDL_Flip(ecran);//actualisation
		}
	//--------------

	}

	return EXIT_SUCCESS;
}








//function to execute the instructions:

int execute_instr(Memoire &mem, int *p_index, SDL_Surface *ecran, Uint32 couleurs[]){
	int p_ind1, p_ind2, i_op = mem[*p_index].getOp();

	switch(i_op){//switch to the different mnemonic
		case DAT:
			return 1;	//unexecutable mnemonic => the warrior is a looser
		case JMP://jump
			switch(mem[*p_index].getAdrA()){
				case 1:	//direct adressing
					*p_index+=mem[*p_index].getArgA();
					break;
				case 2://indirect adressing: @
					*p_index+=mem[*p_index].getArgA();	//we go to the adress given in argA
					*p_index+=mem[*p_index].getArgA();
				default:
					return 2; //there is a problem
			}
			break;
		case MOV:
			p_ind1=*p_index+mem[*p_index].getArgA();	//index on the departure memory cell (which has to be moved)
			p_ind2=*p_index+mem[*p_index].getArgB();	//index on the arrival memory cell

			switch(mem[*p_index].getAdrA()){
				case 2://@
					p_ind1+=mem[p_ind1].getArgA();
				case 1:
					switch(mem[*p_index].getAdrB()){
						case 1:
							break;
						case 2://@
							p_ind2+=mem[p_ind2].getArgA();
							break;
						default:
							return 2; //pb
					}

                    p_ind1=p_ind1%TAILLE_MEM;   //utile ?
                    p_ind2=p_ind2%TAILLE_MEM;
					//copy
					mem[p_ind2].setOp(mem[p_ind1].getOp());
					mem[p_ind2].setAdrA(mem[p_ind1].getAdrA());
					mem[p_ind2].setArgA(mem[p_ind1].getArgA());
					mem[p_ind2].setAdrB(mem[p_ind1].getAdrB());
					mem[p_ind2].setArgB(mem[p_ind1].getArgB());

					mem.setCouleur(p_ind2, p_ind2, ecran, couleurs, 0);
					break;
				case 0://#
					switch(mem[*p_index].getAdrB()){
						case 1:
							break;
						case 2://@
							p_ind2+=mem[p_ind2].getArgA();
							break;
						default:
							return 2; //pb
					}
					p_ind1=p_ind1%TAILLE_MEM;       //utile ?
                    p_ind2=p_ind2%TAILLE_MEM;
					mem[p_ind2].raz(); //to have a "DAT"
					mem[p_ind2].setArgA(mem[*p_index].getArgA());
					mem.setCouleur(p_ind2, p_ind2, ecran, couleurs, 0);
					break;
			}

			break;
		case SUB:	//substract
		case ADD:	//add
			p_ind1=*p_index+mem[*p_index].getArgA();	//index on the departure memory cell (which has to be moved)
			p_ind2=*p_index+mem[*p_index].getArgB();	//index on the arrival cell

			switch(mem[*p_index].getAdrA()){
				case 2://@
					p_ind1+=mem[p_ind1].getArgA();
				case 1:
					switch(mem[*p_index].getAdrB()){
						case 1:
							break;
						case 2://@
							p_ind2+=mem[p_ind2].getArgA();
							break;
						default:
							return 2; //pb
					}

					if(i_op == ADD)
						mem[p_ind2].setArgA(mem[p_ind1].getArgA()+mem[p_ind2].getArgA());//add
					else
						mem[p_ind2].setArgA(mem[p_ind2].getArgA() - mem[p_ind1].getArgA());	//substract

					mem.setCouleur(p_ind2, p_ind2, ecran, couleurs, 0);
					break;
				case 0://#
					switch(mem[*p_index].getAdrB()){
						case 1:
							break;
						case 2://@
							p_ind2+=mem[p_ind2].getArgA();
							break;
						default:
							return 2; //pb
					}
					if(i_op == ADD)
						mem[p_ind2].setArgA(mem[*p_index].getArgA()+mem[p_ind2].getArgA());//Add
					else
						mem[p_ind2].setArgA(mem[p_ind2].getArgA() - mem[*p_index].getArgA());//substract

					mem.setCouleur(p_ind2, p_ind2, ecran, couleurs, 0);
					break;
			}

			break;
		case JMG://jump if B>0
		case JMZ://jump if (B)=0
			p_ind1=*p_index+mem[*p_index].getArgB();//index on the memory cell which has to be compared

			switch(mem[*p_index].getAdrB()){
				case 2://@
					p_ind1+=mem[p_ind1].getArgB();
				case 1:
					if(!((i_op==JMG && mem[p_ind1].getArgA() > 0) || (i_op==JMZ && mem[p_ind1].getArgA() == 0)))
						break;
					switch(mem[*p_index].getAdrA()){
						case 1:
							*p_index+=mem[*p_index].getArgA();
							break;
						case 2:
							*p_index+=mem[*p_index].getArgA();	//go to the adress given in argA
							*p_index+=mem[*p_index].getArgA();
						default:
							return 2; //Problem: there is no case #
					}
					break;
				default:	//no #
					return 2; //pb
			}
			break;
		case DJZ://decremente B and jump to A if the result is equal to 0
			p_ind1=*p_index+mem[*p_index].getArgB();//index to the cell memory which has to be decremented and compared
			switch(mem[*p_index].getAdrB()){
				case 2://@
					p_ind1+=mem[p_ind1].getArgB();
				case 1:
					mem[p_ind1].setArgA(mem[p_ind1].getArgA() - 1);
					if(mem[p_ind1].getArgA() == 0){	//then jump
						switch(mem[*p_index].getAdrA()){
							case 1:	//direct adressing
								*p_index+=mem[*p_index].getArgA();
								break;
							case 2://indirect adressing @
								*p_index+=mem[*p_index].getArgA();	//We go to the adress given in argA
								*p_index+=mem[*p_index].getArgA();
							default:
								return 2; //=pb	: no case #
						}
					}
					break;
				default:	//no case #
					return 2; //pb
			}
			break;
		case CMP:
			p_ind1=*p_index+mem[*p_index].getArgA();	//index on the 1st memory cell
			p_ind2=*p_index+mem[*p_index].getArgB();	//index on the 2nd memory cell
			int val_A=0, val_B=0;

			switch(mem[*p_index].getAdrA()){
				case 2://@
					p_ind1+=mem[p_ind1].getArgA();
				case 1:
					val_A=mem[p_ind1].getArgA();
					break;
				case 0:
					val_A=mem[*p_index].getArgA();
					break;
			}//we have now the first value to be compared

			switch(mem[*p_index].getAdrB()){
				case 2://@
					p_ind2+=mem[p_ind2].getArgA();
				case 1:
					val_B=mem[p_ind2].getArgA();
					break;
				case 0:
					val_B=mem[*p_index].getArgB();
					break;
			}//we have now the second value

			if(val_A != val_B)	//Jump the next instruction if they have not the same value.
				*p_index+=2;

			break;
	}
	return 0;	//no problem
}
